﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Jinjia.Approve.Common.Enum;
using Jinjia.Approve.Entity.Entity.JJFlow;
using Jinjia.Approve.IRepository.JJFlow;
using Jinjia.Approve.IService.JJFlow;
using Jinjia.Approve.IService.JJFlow.Action;
using Jinjia.Approve.Model.Input.JJFlow;
using Jinjia.Approve.Model.VM;
using Jinjia.Approve.Model.VM.JJFlow;
using Jinjia.Approve.Model.VM.JJFlow.DTO;
using JinJia.Core.Base.Exceptions;
using Jinjia.Core.BaseInfrastructure.StorageModel.Model;

namespace Jinjia.Approve.Service.JJFlow.Action
{
    public class JJFLowActionApprove : JJFlowActionGoTo, IJJFLowActionApprove
    {
        private readonly IJJFlowNodeService _jjFlowNodeService;
        private readonly IFlowInstanceEmpRepository _flowInstanceEmpRepository;
        private readonly IFlowNodeReferenceRepository _flowNodeReferenceRepository;
        private readonly IFlowTemplateRepository _flowTemplateRepository;

        public JJFLowActionApprove(IJJFlowInstanceService jjFlowInstanceService,
            IJJFlowTrackService jjFlowTrackService,
            IJJFlowNodeService jjFlowNodeService,
            IFlowInstanceEmpRepository flowInstanceEmpRepository,
            IFlowNodeReferenceRepository flowNodeReferenceRepository,
            IFlowTemplateRepository flowTemplateRepository) : base(jjFlowInstanceService,
            jjFlowTrackService)
        {
            _jjFlowNodeService = jjFlowNodeService;
            _flowInstanceEmpRepository = flowInstanceEmpRepository;
            _flowNodeReferenceRepository = flowNodeReferenceRepository;
            _flowTemplateRepository = flowTemplateRepository;
        }

        public async Task<NodeInfo> Approve(int instance_id, int user_id, string remark, int is_auto_approve = 0)
        {
            var instance = await CheckAndGetFlowInstanceById(instance_id);
            //获取当前操作的节点
            var current_node = await _jjFlowNodeService.GetNodeById(instance.CurrentNodeId);
            //断言有下一个节点
            AssertHasNextNode(current_node);

            //查询参考轨迹
            var reference_list = await _flowNodeReferenceRepository.GetReferences(instance_id);
            var reference_model = reference_list.FirstOrDefault(x => x.node_id == current_node.id);
            if (reference_model == null)
            {
                throw new BusinessException("未找到该节点预计轨迹！");
            }

            reference_list = reference_list.Where(x => x.sequence > reference_model.sequence).ToList();
            var reference_node = reference_list.First();
            //断言是否操作过此节点
            AssertExistTrack(user_id, reference_node.node_id, instance_id);
            //断言可审核人
            AssertApprover(user_id, reference_node.node_id, instance.TemplateId, instance_id);
            //通过的当前节点信息
            var approve_node = await _jjFlowNodeService.GetNodeById(reference_node.node_id);
            //是否还有审核人
            var is_auditor = false;
            var nodeInfo = new NodeInfo();
            if (approve_node.emp_type == 1) //会签
            {
                //是否其他人 已经审批完
                if (await IsApprovalCompleted(user_id, approve_node.id, instance_id))
                {
                    await Pass(instance, nodeInfo, approve_node, user_id, remark, reference_node.node_id, is_auto_approve);
                }
                else
                {
                    is_auditor = true;
                    //更新新节点到instance
                    instance.CurrentNodeId = current_node.id;
                    instance.UpdateUserId = user_id;
                    instance.UpdateTime = DateTime.Now;
                    await _jjFlowInstanceService.Save(instance);
                    //生成 track记录
                    await RecordTrackInfo(approve_node, instance_id, user_id, (int)EnumDb.JJFlowOperationTypeEnum.Approve, user_id, remark, is_auto_approve);
                    nodeInfo.info = new BaseBoVM<Node>(approve_node);
                    nodeInfo.isComplete = false;
                }
            }
            else
            {
                var template = await _flowTemplateRepository.GetById(instance.TemplateId);
                if (template == null) throw new BusinessException("审批失败，审批模板不存在！");
                //提交人与审核人一致的情况下
                if (template.is_submit_user_check == 0 && user_id == instance.CreateUserId)
                {
                    var node_sequence = await _flowNodeReferenceRepository.GetNodeByInstanceIdAndNodeId(instance_id, instance.CurrentNodeId);
                    if (node_sequence == null) throw new BusinessException("审批失败，节点执行顺序不存在！");
                    var sequence = node_sequence.sequence + 1;
                    var approver_list = new List<jj_flow_instance_emp>();
                    //获取过去节点已审批人
                    var formerly_user_list = await _flowInstanceEmpRepository.GetFormerlyNodeApprover(instance_id, sequence);
                    approver_list.AddRange(formerly_user_list);
                    //获取未来节点所有审批人
                    var future_user_list = await _flowInstanceEmpRepository.GetFutureNodeApprover(instance_id, sequence);
                    approver_list.AddRange(future_user_list);
                    //审批人去重
                    var approver = approver_list.Where(a => a.user_id != user_id).Select(a => a.user_id).Distinct().ToList();
                    if (approver.Count == 0)
                    {
                        throw new BusinessException("审批失败，提交人与所有审批人不能是同一个！");
                    }
                }

                //或签
                await Pass(instance, nodeInfo, approve_node, user_id, remark, reference_node.node_id, is_auto_approve);
            }

            //更改自己的标记为已完成
            var emp_data = await _flowInstanceEmpRepository.GetUserInstanceEmp(user_id, approve_node.id, instance_id);
            emp_data.is_complete = 1;
            emp_data.update_time = DateTime.Now;
            await _flowInstanceEmpRepository.Save(emp_data);

            //获取剩余待审核人
            if (is_auditor)
            {
                nodeInfo.emp_user = await GetNotReviewedUser(approve_node.id, instance_id, instance.TemplateId);
            }

            return nodeInfo;
        }

        public async Task<List<jj_flow_instance_emp>> GetInstanceEmp(string biz_order_id, string modular_key)
        {
            var instanceNodeEmp = await _flowInstanceEmpRepository.GetInstanceEmpByBIdAndNId(biz_order_id, modular_key);
            return instanceNodeEmp;
        }

        public async Task<bool> GetUserPower(string system_key, string big_modular_key, string modular_key, int user_id)
        {
            return await _flowInstanceEmpRepository.GetUserPower(system_key, big_modular_key, modular_key, user_id);
        }

        public async Task<List<string>> GetUserProcessedBizOrderId(string system_key, string big_modular_key, string modular_key, int user_id)
        {
            return await _jjFlowInstanceService.GetUserProcessedBizOrderId(system_key, big_modular_key, modular_key, user_id);
        }

        public async Task<List<string>> GetUserCreateApplyBizOrderId(string system_key, string big_modular_key, string modular_key, int user_id)
        {
            return await _jjFlowInstanceService.GetUserCreateApplyBizOrderId(system_key, big_modular_key, modular_key, user_id);
        }

        public async Task<PageListSearchResultVM<JJInstanceViewModel>> GetInstancePageList(JJInstanceSearchCondition searchCondition, int user_id)
        {
            return await _jjFlowInstanceService.GetInstancePageList(searchCondition, user_id);
        }

        public async Task<UserPowerResponse> CheckUserPower(CheckQueryRequest request)
        {
            var template_id = await _flowTemplateRepository.GetTemplateId(request.system_key, request.big_modular_key, request.modular_key);
            if (template_id == 0)
            {
                return new UserPowerResponse()
                {
                    is_revoke = false,
                    is_reciew = false
                };
            }

            var instance_info = await _jjFlowInstanceService.GetInstanceInfo(request.modular_key, request.biz_order_id);
            if (instance_info == null)
            {
                return new UserPowerResponse()
                {
                    is_revoke = false,
                    is_reciew = false
                };
            }

            //状态为审批中，才显示撤回按钮
            var is_rovoke = instance_info.Status == "0" && instance_info.CreateUserId == request.user_id;

            var instance_ids = await _flowInstanceEmpRepository.GetUserBizOrderId(request.modular_key, request.user_id);

            if (instance_ids == null || instance_ids.Count == 0)
            {
                return new UserPowerResponse()
                {
                    is_reciew = false,
                    is_revoke = is_rovoke
                };
            }

            var result_count = instance_ids.Count(x => x == instance_info.BizOrderId);

            return new UserPowerResponse()
            {
                is_reciew = result_count > 0,
                is_revoke = is_rovoke
            };
        }

        /// <summary>
        /// 其他人是否审批通过
        /// </summary>
        /// <param name="user_id"></param>
        /// <param name="node_id"></param>
        /// <param name="instance_id"></param>
        /// <returns></returns>
        private async Task<bool> IsApprovalCompleted(int user_id, int node_id, int instance_id)
        {
            return await _flowInstanceEmpRepository.IsApprovalCompleted(user_id, node_id, instance_id);
        }

        /// <summary>
        /// 通过
        /// </summary>
        /// <param name="user_id"></param>
        /// <param name="nodeInfo"></param>
        /// <param name="remark"></param>
        /// <param name="reference_node_id"></param>
        /// <param name="approve_node"></param>
        /// <param name="instance"></param>
        /// <param name="is_auto_approve"></param>
        private async Task Pass(JjFlowInstanceVM instance, NodeInfo nodeInfo, Node approve_node, int user_id, string remark, int reference_node_id, int is_auto_approve = 0)
        {
            //获取通过后的下一个节点
            var next_node = await _jjFlowNodeService.GetNextNode(instance.Id, reference_node_id);
            //更新新节点到instance
            instance.CurrentNodeId = reference_node_id;
            if (next_node.node_type == (int)EnumDb.JJFlowNodeTypeEnum.EndNode)
            {
                instance.EndNodeId = next_node.id;
                instance.EndUser = user_id;
                instance.Status = "20"; //已完成
                instance.CurrentNodeId = next_node.id;
                nodeInfo.isComplete = true;
            }
            else
            {
                nodeInfo.info = new BaseBoVM<Node>(next_node);
                nodeInfo.isComplete = false;
                nodeInfo.emp_user = await GetNotReviewedUser(next_node.id, instance.Id, approve_node.template_id);
            }

            instance.UpdateUserId = user_id;
            instance.UpdateTime = DateTime.Now;
            await _jjFlowInstanceService.Save(instance);
            //生成 track记录
            await RecordTrackInfo(approve_node, instance.Id, user_id, (int)EnumDb.JJFlowOperationTypeEnum.Approve, user_id, remark, is_auto_approve);
            //下一个节点是审批通过，新增一条track记录
            if (next_node.node_type == (int)EnumDb.JJFlowNodeTypeEnum.EndNode)
            {
                //生成 自动完成track记录
                await RecordTrackInfo(next_node, instance.Id, user_id, (int)EnumDb.JJFlowOperationTypeEnum.Approve, user_id, remark, is_auto_approve);
            }
        }

        public async Task<List<EmpInfo>> GetNotReviewedUser(int node_id, int instance_id, int template_id)
        {
            var empInfos = await _flowInstanceEmpRepository.GetInstanceNodeEmp(node_id, instance_id, template_id, 0);
            return empInfos;
        }

        public async Task<List<EmpInfo>> GetReviewedUser(int node_id, int instance_id, int template_id, int is_complete)
        {
            var empInfos = await _flowInstanceEmpRepository.GetInstanceNodeEmp(node_id, instance_id, template_id, is_complete);
            return empInfos;
        }
    }
}